package huanyuxingcheng.nonameinstallhelper;

import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
import android.widget.ProgressBar;
import android.widget.TextView;

import net.lingala.zip4j.ZipFile;
import net.lingala.zip4j.model.FileHeader;
import net.lingala.zip4j.progress.ProgressMonitor;

import org.zeroturnaround.zip.NameMapper;
import org.zeroturnaround.zip.ZipUtil;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.Charset;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;


public class ZipActivity extends BaseActivity {

    private String fromPath;
    private String toPath;

    private File fromFile;

    private File toFile;

    private String encoding = "UTF-8";
    /**
     * 正在安装中
     */
    private TextView mMainText;
    private ProgressBar mProgressBar;

    private TextView mStatusText;

    private StringBuilder sb = new StringBuilder();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_zip);
        initView();
        Intent intent = getIntent();
        fromPath = intent.getStringExtra("fromPath");
        toPath = intent.getStringExtra("toPath");
        if (fromPath == null || !fromPath.endsWith(".zip")) {
            showShortToast("文件错误！");
            finish();
            return;
        }
        File file = new File(fromPath);
        if (!file.exists() || !file.isFile()) {
            showShortToast("文件不存在！");
            finish();
            return;
        }
        if (toPath == null) {
            showShortToast("输出路径错误！");
            finish();
            return;
        }
        file = new File(toPath);
        if (!file.exists() || !file.isDirectory()) {
            showShortToast("输出路径错误！");
            finish();
            return;
        }
        startZip();
    }

    private Runnable runnable = new Runnable() {
        @Override
        public void run() {
            boolean success = false;
            boolean cancelled = false;
            try {
                updateText("开始使用ZIP4J解压缩");
                updateProgress(0);
                encoding = getEncoding(fromFile.getPath());
                ZipFile zipFile = new ZipFile(fromFile);
                ProgressMonitor progressMonitor = zipFile.getProgressMonitor();
                zipFile.setRunInThread(true);
                zipFile.setCharset(Charset.forName(encoding));
                zipFile.extractAll(toFile.getAbsolutePath());
                while (!progressMonitor.getState().equals(ProgressMonitor.State.READY)) {
                    updateProgress(progressMonitor.getPercentDone());
                    updateText("解压进度"+(progressMonitor.getPercentDone())+"%");
                    Thread.sleep(100);
                }
                if (progressMonitor.getResult().equals(ProgressMonitor.Result.SUCCESS)) {
                    updateProgress(100);
                    updateText("解压成功！请离开此页面。");
                    success = true;
                } else if (progressMonitor.getResult().equals(ProgressMonitor.Result.ERROR)) {
                    updateText("解压出现错误！可能是你手机"+ Build.MODEL+"不兼容。请截图并在群里@寰宇星城 报告以下异常信息：\n解压工具：ZIP4J\n"+progressMonitor.getException().getMessage());
                } else if (progressMonitor.getResult().equals(ProgressMonitor.Result.CANCELLED)) {
                    updateText("解压任务被取消。");
                    cancelled = true;
                }
            }catch (Exception e){
                updateText("解压出现错误！可能是你手机"+ Build.MODEL+"不兼容。请截图并在群里@寰宇星城 报告以下异常信息：\n解压工具：ZIP4J\n"+e.getMessage());
            }
            if(!success && !cancelled){
                try {
                    updateText("将尝试使用zt-zip解压");
                    updateProgress(0);
                    final double[] p = new double[1];
                    ZipUtil.unpack(fromFile, toFile, new NameMapper() {
                        @Override
                        public String map(String name) {
                            updateText("解压" + name);
                            p[0] = p[0] * 0.95;
                            updateProgress((int) (100 - (100 * p[0])));
                            return name;
                        }
                    },Charset.forName(encoding));
                    success = true;
                    updateText("解压成功！");
                }catch (RuntimeException e){
                    updateText("解压出现错误！可能是你手机"+ Build.MODEL+"不兼容。请截图并在群里@寰宇星城 报告以下异常信息：\n解压工具：zt-zip\n"+e.getMessage());
                }
            }
            if(!success && !cancelled){
                try {
                    updateText("将尝试使用JAVA自带的解压缩工具");
                    decompressFile(toFile.getAbsolutePath(), fromFile.getAbsolutePath(), new ProgressCallback() {
                        @Override
                        public void onProgress(double d, String name) {
                            updateProgress((int) (100 * d));
                            updateText("解压文件："+name);
                        }
                    });
                    success = true;
                }catch (Exception e){
                    updateText("解压出现错误！可能是你手机"+ Build.MODEL+"不兼容。请截图并在群里@寰宇星城 报告以下异常信息：\n解压工具：java.util\n"+e.getMessage());
                }
            }
            if(!success){
                updateText("解压失败！");
            }else{
                updateText("解压成功！3秒后将自动关闭，请打开游戏查看安装成果。");
                new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        if(!isDestroyed()) {
                            finish();
                        }
                    }
                },3000);
            }
        }
    };

    private static final String MAC_IGNORE = "__MACOSX/";

    public interface ProgressCallback{

        void onProgress(double d,String name);

    }

    private static boolean isMessyCode(String str) {
        for (int i = 0; i < str.length(); i++) {
            char c = str.charAt(i);
            // 当从Unicode编码向某个字符集转换时，如果在该字符集中没有对应的编码，则得到0x3f（即问号字符?）
            // 从其他字符集向Unicode编码转换时，如果这个二进制数在该字符集中没有标识任何的字符，则得到的结果是0xfffd
            if ((int) c == 0xfffd) {
                // 存在乱码
                return true;
            }
        }
        return false;
    }

    private static String getEncoding(String path) throws Exception {
        String encoding = "GBK";
        net.lingala.zip4j.ZipFile zipFile = new net.lingala.zip4j.ZipFile(path);
        zipFile.setCharset(Charset.forName(encoding));
        List<FileHeader> list = zipFile.getFileHeaders();
        for (int i = 0; i < list.size(); i++) {
            FileHeader fileHeader = list.get(i);
            String fileName = fileHeader.getFileName();
            if (isMessyCode(fileName)) {
                encoding = "UTF-8";
                break;
            }
        }
        return encoding;
    }

    public static void decompressFile(String target, String source,ProgressCallback callback) throws Exception {
        if(TextUtils.isEmpty(target)){
            throw new Exception("error target");
        }
            File file = new File(source);
            if(!file.exists()) {
                return;
            }
            java.util.zip.ZipFile zipFile = new java.util.zip.ZipFile(file);
            ZipInputStream zipInputStream = new ZipInputStream(new FileInputStream(file));
            ZipEntry zipEntry = null;
            long current = 0;
            long total = zipFile.size();

            while ((zipEntry = zipInputStream.getNextEntry()) != null) {
                String fileName = zipEntry.getName();
                if(fileName != null && fileName.contains(MAC_IGNORE)) {
                    continue;
                }
                File temp = new File(target + File.separator + fileName);
                if(zipEntry.isDirectory()) {
                    File dir = new File(target + File.separator + fileName);
                    dir.mkdirs();
                    continue;
                }
                if (temp.getParentFile() != null && !temp.getParentFile().exists()) {
                    temp.getParentFile().mkdirs();
                }
                byte[] buffer = new byte[1024];
                OutputStream os = new FileOutputStream(temp);
                InputStream is = zipFile.getInputStream(zipEntry);
                int len = 0;
                while ((len = is.read(buffer)) != -1) {
                    os.write(buffer, 0, len);
                }
                os.close();
                is.close();
                current += zipEntry.getCompressedSize();
                callback.onProgress(current/(double)total,zipEntry.getName());
            }
            zipInputStream.close();

    }

    private void updateText(String text){
        sb.insert(0,text+"\n");
        final String str = sb.toString();
        if(sb.length() > 5000){
            sb.delete(5001,sb.length());
        }
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                mStatusText.setText(str);
            }
        });
    }

    private void updateProgress(final int progress){
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                mProgressBar.setProgress(progress);
            }
        });
    }

    private void startZip() {
        fromFile = new File(fromPath);
        toFile = new File(toPath);
        new Thread(runnable).start();
    }

    private void initView() {
        mMainText = findViewById(R.id.main_text);
        mProgressBar = findViewById(R.id.progress_bar);
        mStatusText = findViewById(R.id.status_text);
    }
}
